package com.file.system.plugin.shiro;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.file.system.entity.dict.IsSuperAdmin;
import com.file.system.entity.dict.OnOff;
import com.file.system.entity.system.WebMenu;
import com.file.system.entity.system.WebUser;
import com.file.system.plugin.websocket.PublicTask;
import com.file.system.service.system.IWebUserService;
import com.file.system.service.system.ShiroService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.web.subject.support.DefaultWebSubjectContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static cn.hutool.core.util.ObjectUtil.isNotEmpty;
import static com.file.system.tools.Formater.getTime;

/**
 * @author jch
 * @Description (shiro)
 * @date
 */
public class CustomRealm extends AuthorizingRealm {

    @Autowired
    @Lazy
    private IWebUserService iWebUserService;
    @Autowired
    private SessionDAO sessionDAO;
    @Autowired
    private ShiroService shiroService;
    @Autowired
    private AccessControl accessControl;


    /**
     * 获取匿名路径
     */
    public List<String> getAnonPath() {
        return accessControl.getAnonPath();
    }

    /**
     * 获取所有认证信息
     */
    public String getAllAuth() {
        return accessControl.getAllAuth();
    }

    /**
     * 初始化菜单授权
     */
    public void initMenuAuth(Map<String, String> chainMap) {
        // 查询未删除的菜单
        List<WebMenu> menuList = shiroService.list(new QueryWrapper<WebMenu>()
                .eq("a.is_del", "0")
        );

        // 遍历查询到的菜单，如果菜单路径不为空，则获取该路径下的权限
        menuList.stream()
                .filter(menu -> isNotEmpty(menu.getPath()))
                .forEach(menu -> {
                    // 获取该路径下的权限
                    String auths = menuList.stream()
                            .filter(m -> ObjectUtil.equal(menu.getPath(), m.getPath()))
                            .map(WebMenu::getAuth)
                            .distinct()
                            .collect(Collectors.joining(","));
                    // 将路径和权限放入chainMap中
                    chainMap.put(menu.getPath(), "roleOrFilter[" + auths + "]");
                });
    }

    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) throws AuthenticationException {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        WebUser user = ShiroTools.getShiroUser();

        List<WebMenu> menuList;

        // 获取所有菜单
        menuList = shiroService.list(new QueryWrapper<WebMenu>().eq("a.is_del", "0"));

        // 获取当前用户菜单的权限
        Set<String> authSet = menuList.stream().filter(menu -> isNotEmpty(menu.getPath())).map(WebMenu::getAuth).collect(Collectors.toSet());

        // 添加角色
        info.addRoles(authSet);
        return info;
    }

    /**
     * 获取即将需要认证的信息
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
        // 已有登录用户退出当前登录用户
        WebUser loginUser = ShiroTools.getShiroUser();
        if (loginUser != null) {
            SecurityUtils.getSubject().logout();
        }

        UsernamePasswordToken uptoken = (UsernamePasswordToken) token;
        String username = uptoken.getUsername();
        String password = String.valueOf(uptoken.getPassword());

        WebUser user = iWebUserService.getOne(new QueryWrapper<WebUser>()
                .eq("a.username", username)
                .eq("a.password", password)
                .eq("a.is_del", "0")
        );

        // 用户名或密码错误
        if (ObjectUtil.isNull(user)) {
            //登录失败次数+1
            throw new AccountException("用户名或密码错误");
        }
        // 已禁用
        /*if (ObjectUtil.equal(user.getDictOnOff(), OnOff.OFF.val)) {
            throw new DisabledAccountException("账号已禁用");
        }*/

        // 踢出其他浏览器登录用户
        // removeOtherUser(user);

        // 修改最后登录时间
        /*user.setLastLoginTime(getTime("yyyy-MM-dd HH:mm:ss"));
        boolean state = iWebUserService.updateById(user);
        if (!state) {
            throw new AccountException("记录登录时间错误");
        }

        // 推送系统公告
        PublicTask publicTask = new PublicTask(ShiroTools.getSession().getId().toString());
        new Thread(publicTask).start();*/

        return new SimpleAuthenticationInfo(user, password, this.getName());
    }


    /**
     * 踢出其他浏览器登录用户
     */
    private void removeOtherUser(WebUser user) {
        //获取当前激活的会话
        Collection<Session> sessions = sessionDAO.getActiveSessions();
        //遍历会话
        for (Session session : sessions) {
            //获取会话的属性
            Object sessionPrincipals = session.getAttribute(DefaultWebSubjectContext.PRINCIPALS_SESSION_KEY);
            //如果属性为空，则跳过
            if (ObjectUtil.isNull(sessionPrincipals)) {
                continue;
            }

            //将属性转换为SimplePrincipalCollection
            SimplePrincipalCollection principalCollection = (SimplePrincipalCollection) sessionPrincipals;
            //获取主用户
            WebUser temp = (WebUser) principalCollection.getPrimaryPrincipal();
            //如果主用户id和传入的id相同，则删除会话
            if (ObjectUtil.equal(user.getId(), temp.getId())) {
                /*WebSocketServer.sendMessage(USER_OTHER_LOGIN, USER_OTHER_LOGIN.getMessage(), session.getId().toString());*/
                sessionDAO.delete(session);
                break;
            }
        }
    }


    /**
     * 重写方法,清除当前用户的的 授权缓存
     *
     * @param principals
     */
    @Override
    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
        super.clearCachedAuthorizationInfo(principals);
    }

    /**
     * 重写方法，清除当前用户的 认证缓存
     *
     * @param principals
     */
    @Override
    public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
        super.clearCachedAuthenticationInfo(principals);
    }

    @Override
    public void clearCache(PrincipalCollection principals) {
        super.clearCache(principals);
    }
}
